package com.example.chat03.controller;

import com.example.chat03.config.RabbitConfig;
import com.example.chat03.model.StompAuthenticatedUser;
import com.example.chat03.model.WebSocketMsg;
import com.example.chat03.model.WebSocketMsgDTO;
import com.example.chat03.service.ChatService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.stream.Collectors;

@Controller
public class ChatController {

    private static final Logger logger = LoggerFactory.getLogger(ChatController.class);

    @Autowired
    private SimpUserRegistry simpUserRegistry;
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;
    @Autowired
    ChatService chatService;
    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 模板引擎为Thymeleaf，需要加上spring-boot-starter-thymeleaf依赖
     */
    @GetMapping("/page/chat")
    public ModelAndView turnToChatPage(){
        return new ModelAndView("chat");
    }

    /**
     * 群聊消息处理
     * 这里我们通过 @SendTo 注解指定消息目的地为"/topic/chat-group"，如果不加该注解则会自动发送到"/topic"+"/chat-group"
     * @param webSocketMsgDTO 请求参数，消息处理器会自动将JSON字符串转换为对象
     * @return 消息内容，方法返回值将会广播给所有订阅"/topic/chat-group"的客户端
     */
    @MessageMapping("/chat/group")
    @SendTo("/topic/chat-group")
    public WebSocketMsg groupChat(WebSocketMsgDTO webSocketMsgDTO) throws JsonProcessingException {
        logger.info("群聊消息接受: {}",new ObjectMapper().writeValueAsString(webSocketMsgDTO));
        String content = String.format("来自[%s]的群聊消息: %s", webSocketMsgDTO.getName(), webSocketMsgDTO.getContent());
        return WebSocketMsg.builder().content(content).build();
    }

    /**
     * 私聊消息处理 1（自己发送自己接受）
     * 这里我们通过 @SendToUser 注解指定消息目的地为"/topic/chat-private"，发送目的地默认会拼接上"/user/"前缀
     * 实际发送目的地为"/user/topic/chat-private"
     * @param webSocketMsgDTO 请求参数，消息处理器会自动将JSON字符串转换为对象
     * @return 消息内容，方法返回值将会基于SessionID单播给指定用户
     */
    @MessageMapping("/chat/private1")
    @SendToUser("/topic/chat-private1")
    public WebSocketMsg private1Chat(WebSocketMsgDTO webSocketMsgDTO) throws JsonProcessingException {
        logger.info("私聊（自己发送自己接受）消息接受: {}",new ObjectMapper().writeValueAsString(webSocketMsgDTO));
        String content = "私聊（自己发送自己接受）消息回复：" + webSocketMsgDTO.getContent();
        return WebSocketMsg.builder().content(content).build();
    }

    /**
     * 私聊消息处理 2（自己发送他人接受）
     * 这里我们通过 convertAndSendToUser 方法指定发送给的用户 以及消息目的地为"/topic/chat-private2"，发送目的地默认会拼接上"/user/"前缀
     * 实际发送目的地为"/user/topic/chat-private"
     * @param webSocketMsgDTO 请求参数，消息处理器会自动将JSON字符串转换为对象
     */
    @MessageMapping("/chat/private2")
    public void private2Chat(WebSocketMsgDTO webSocketMsgDTO) throws JsonProcessingException {
        logger.info("私聊（自己发送他人接受）消息接受: {}",new ObjectMapper().writeValueAsString(webSocketMsgDTO));
        String content = String.format("私聊（自己发送他人接受）消息回复：来自[%s]的私聊消息：%s", webSocketMsgDTO.getName(), webSocketMsgDTO.getContent());
//        simpMessagingTemplate.convertAndSendToUser(webSocketMsgDTO.getTo(),"/topic/chat-private2",WebSocketMsg.builder().content(content).build());
        sendMessage(webSocketMsgDTO);
    }

    /**
     * 定时消息推送，这里我们会列举所有在线的用户，然后单播给指定用户。
     * 通过 SimpMessagingTemplate 实例可以在任何地方推送消息。
     */
//    @Scheduled(fixedRate = 10 * 1000)
    public void pushMessageAtFixedRate(){
        logger.info("当前在线人数: {}",simpUserRegistry.getUserCount());
        if (simpUserRegistry.getUserCount() <= 0){
            return;
        }
        // 这里的Principal为StompAuthenticatedUser实例
        Set<StompAuthenticatedUser> users = simpUserRegistry.getUsers().stream()
                .map(simpUser -> (StompAuthenticatedUser) simpUser.getPrincipal()).collect(Collectors.toSet());

        users.forEach(stompAuthenticatedUser -> {
            String username = stompAuthenticatedUser.getUsername();
            String content = String.format("定时推送的私聊消息, 接收人: %s, 时间: %s",username, LocalDateTime.now());
            logger.info("开始推送消息给指定用户, username: {}, 消息内容:{}",username,content);
            simpMessagingTemplate.convertAndSendToUser(username,"/topic/chat-push",WebSocketMsg.builder().content(content).build());
        });

    }

    public void sendMessage(WebSocketMsgDTO webSocketMsgDTO) {
        try {
            String json = new ObjectMapper().writeValueAsString(webSocketMsgDTO);
            logger.info("json:{}", json);
            rabbitTemplate.convertAndSend(RabbitConfig.MQ_EXCHANGE,webSocketMsgDTO.getTo(),json);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
